/**
 * Copyright (c) iwindplus Technologies Co., Ltd.2024-2030, All rights reserved.
 */

package com.iwindplus.boot.web;

import cn.hutool.core.text.CharSequenceUtil;
import com.iwindplus.boot.web.domain.property.FilterProperty;
import com.iwindplus.boot.web.domain.property.OkHttpClientProperty;
import com.iwindplus.boot.web.interceptor.OkHttpClientInterceptor;
import com.iwindplus.boot.web.manager.http.OkHttpClientManager;
import jakarta.annotation.Resource;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import okhttp3.ConnectionPool;
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;

/**
 * OkHttp配置.
 *
 * @author zengdegui
 * @since 2023/08/31
 */
@Slf4j
@Configuration
@EnableConfigurationProperties({OkHttpClientProperty.class, FilterProperty.class})
@ConditionalOnProperty(prefix = "okhttp.client", name = "enabled", havingValue = "true", matchIfMissing = true)
public class OkHttpClientConfiguration {

    @Resource
    private OkHttpClientProperty property;

    /**
     * 创建 ConnectionPool
     *
     * @return ConnectionPool
     */
    @Bean
    @ConditionalOnMissingBean({ConnectionPool.class})
    public ConnectionPool okHttpClientConnectionPool() {
        Integer maxConnTotal = this.property.getMaxConnTotal();
        Duration connectionKeepAlive = this.property.getConnectionKeepAlive();
        ConnectionPool connectionPool = new ConnectionPool(maxConnTotal, connectionKeepAlive.toSeconds(), TimeUnit.SECONDS);
        log.info("OkHttpClient ConnectionPool={}", connectionPool);
        return connectionPool;
    }

    /**
     * 创建 OkHttpClient.
     *
     * @param connectionPool          连接池
     * @param okHttpClientInterceptor OkHttpClient拦截器
     * @return OkHttpClient
     */
    @Bean
    public OkHttpClient okHttpClient(ConnectionPool connectionPool, OkHttpClientInterceptor okHttpClientInterceptor) {
        List<Protocol> protocols = this.property.getProtocols().stream().map(Protocol::valueOf).toList();
        OkHttpClient.Builder builder = new OkHttpClient().newBuilder()
            .protocols(protocols)
            .connectionPool(connectionPool)
            .connectTimeout(this.property.getConnectTimeout())
            .readTimeout(this.property.getReadTimeout())
            .writeTimeout(this.property.getWriteTimeout())
            .callTimeout(this.property.getCallTimeout())
            .retryOnConnectionFailure(this.property.getEnableRetry())
            .followRedirects(this.property.getFollowRedirects())
            .addInterceptor(okHttpClientInterceptor);
        if (Boolean.TRUE.equals(this.property.getProxyEnable())) {
            builder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(this.property.getProxyHost(), this.property.getProxyPort())));
            String proxyUsername = this.property.getProxyUsername();
            String proxyPassword = this.property.getProxyPassword();
            if (CharSequenceUtil.isNotBlank(proxyUsername) && CharSequenceUtil.isNotBlank(proxyPassword)) {
                builder.proxyAuthenticator((route, response) -> {
                    String credential = Credentials.basic(proxyUsername, proxyPassword);
                    return response.request().newBuilder().header(HttpHeaders.PROXY_AUTHORIZATION, credential).build();
                });
            }
        }
        OkHttpClient okHttpClient = builder.build();
        log.info("OkHttpClient={}", okHttpClient);
        return okHttpClient;
    }

    /**
     * 创建 OkHttpClientInterceptor.
     *
     * @return OkHttpClientInterceptor
     */
    @Bean
    public OkHttpClientInterceptor okHttpClientInterceptor() {
        OkHttpClientInterceptor okHttpClientInterceptor = new OkHttpClientInterceptor();
        log.info("OkHttpClientInterceptor={}", okHttpClientInterceptor);
        return okHttpClientInterceptor;
    }

    /**
     * 创建 OkHttpClientManager.
     *
     * @return OkHttpClientManager
     */
    @Bean
    @ConditionalOnBean(OkHttpClient.class)
    public OkHttpClientManager okHttpClientManager() {
        OkHttpClientManager okHttpClientManager = new OkHttpClientManager();
        log.info("OkHttpClientManager={}", okHttpClientManager);
        return okHttpClientManager;
    }
}
